//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_sprit_api_serv

import (
	"context"
	"strconv"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_entry_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_sprit_api"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectSpritApiImpl) UpdateBurnDown(ctx context.Context, req *project_sprit_api.UpdateBurnDownRequest) (*project_sprit_api.UpdateBurnDownResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_sprit_api.UpdateBurnDownResponse{
			Code:   project_sprit_api.UpdateBurnDownResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_sprit_api.UpdateBurnDownResponse{
			Code:   project_sprit_api.UpdateBurnDownResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_sprit_api.UpdateBurnDownResponse{
			Code:   project_sprit_api.UpdateBurnDownResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_sprit_api.UpdateBurnDownResponse{
			Code:   project_sprit_api.UpdateBurnDownResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin || sessionItem.UserId == req.MemberUserId) {
		return &project_sprit_api.UpdateBurnDownResponse{
			Code:   project_sprit_api.UpdateBurnDownResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.SpritId, req.ProjectId)
	if err != nil {
		return &project_sprit_api.UpdateBurnDownResponse{
			Code:   project_sprit_api.UpdateBurnDownResponse_CODE_NO_SPRIT,
			ErrMsg: "迭代不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT) {
		return &project_sprit_api.UpdateBurnDownResponse{
			Code:   project_sprit_api.UpdateBurnDownResponse_CODE_NO_SPRIT,
			ErrMsg: "迭代不存在",
		}, nil
	}

	hasUpdatePerm := api_common.CheckEntryCanUpdate(sessionItem, projectItem, roleItem, entryItem)

	if !hasUpdatePerm {
		return &project_sprit_api.UpdateBurnDownResponse{
			Code:   project_sprit_api.UpdateBurnDownResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	startDayStr := time.UnixMilli(entryItem.ExtraSpritInfo.StartTime).Format("20060102")
	endDayStr := time.UnixMilli(entryItem.ExtraSpritInfo.EndTime).Format("20060102")
	startDay, err := strconv.Atoi(startDayStr)
	if err != nil {
		return nil, err
	}
	endDay, err := strconv.Atoi(endDayStr)
	if err != nil {
		return nil, err
	}
	if req.Day < uint32(startDay) || req.Day > uint32(endDay) {
		return &project_sprit_api.UpdateBurnDownResponse{
			Code:   project_sprit_api.UpdateBurnDownResponse_CODE_OUT_OF_DAY,
			ErrMsg: "不在迭代时间区间",
		}, nil
	}
	//检查休息日
	for _, nonWorkDayTime := range entryItem.ExtraSpritInfo.NonWorkDayList {
		nonWorkDayStr := time.UnixMilli(nonWorkDayTime).Format("20060102")
		nonWorkDay, err := strconv.Atoi(nonWorkDayStr)
		if err != nil {
			return nil, err
		}
		if nonWorkDay == int(req.Day) {
			return &project_sprit_api.UpdateBurnDownResponse{
				Code:   project_sprit_api.UpdateBurnDownResponse_CODE_OUT_OF_DAY,
				ErrMsg: "命中非工作日",
			}, nil
		}
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.BurnDownInfoDao.Set(sessCtx, &issue_dao.BurnDownInfoDbItem{
			SpritId:       req.SpritId,
			Day:           req.Day,
			MemberUserId:  req.MemberUserId,
			RemainMinutes: req.RemainMinutes,
		})
		if err != nil {
			return nil, err
		}
		return &project_sprit_api.UpdateBurnDownResponse{
			Code: project_sprit_api.UpdateBurnDownResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_sprit_api.UpdateBurnDownResponse), nil
}

func (apiImpl *ProjectSpritApiImpl) ListBurnDown(ctx context.Context, req *project_sprit_api.ListBurnDownRequest) (*project_sprit_api.ListBurnDownResponse, error) {
	emptyList := []*project_sprit_api.BurnDownInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_sprit_api.ListBurnDownResponse{
			Code:     project_sprit_api.ListBurnDownResponse_CODE_WRONG_SESSION,
			ErrMsg:   "会话不存在",
			InfoList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_sprit_api.ListBurnDownResponse{
			Code:     project_sprit_api.ListBurnDownResponse_CODE_NO_PROJECT,
			ErrMsg:   "项目不存在",
			InfoList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_sprit_api.ListBurnDownResponse{
			Code:     project_sprit_api.ListBurnDownResponse_CODE_NO_PERMISSION,
			ErrMsg:   "没有权限",
			InfoList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}
	exist, err := issue_dao.SpritDao.Exist(ctx, req.ProjectId, req.SpritId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_sprit_api.ListBurnDownResponse{
			Code:     project_sprit_api.ListBurnDownResponse_CODE_NO_SPRIT,
			ErrMsg:   "迭代不存在",
			InfoList: emptyList,
		}, nil
	}
	itemList, err := issue_dao.BurnDownInfoDao.ListBySprit(ctx, req.SpritId)
	if err != nil {
		return nil, err
	}
	infoList := []*project_sprit_api.BurnDownInfo{}
	for _, item := range itemList {
		infoList = append(infoList, item.ToBurnDownInfo())
	}
	return &project_sprit_api.ListBurnDownResponse{
		Code:     project_sprit_api.ListBurnDownResponse_CODE_OK,
		InfoList: infoList,
	}, nil
}
